// =================================================================
// File: delete_blocks.cpp
// Desc: Contains function for freeing up data blocks in filesystem
// =================================================================

// =================================================================
// INCLUDES
// =================================================================

#include <string>
#include "Inode.h"
#include "FSManager.h"
#include "commands.h"
#include "IndirectBlock.h"
#include "config.h"

using namespace std;

// =================================================================
// FUNCTIONS
// =================================================================

// =================================================================
// Name: delete_blocks
// Desc: Deallocates free data blocks and adds them to free block
//       list
// Args: Inode* node - inode of file to free blocks from
//       FSManager* fsm - pointer to FSManager object in use
// =================================================================
void delete_blocks(Inode *node, FSManager *fsm){

    int bytes = node->GetSize();
    int file_offset = 0;

    while (file_offset < bytes)
    {

        int block_index = file_offset / BLOCK_SIZE;
        IndirectBlock *iBlock;

        int block;

        if (file_offset < BLOCK_SIZE*NUM_DIRECT_LINKS)
        {
            // Do direct fetch
            block = node->GetBlockLocation(block_index);
        }
        else if (file_offset < BLOCK_SIZE*(NUM_DIRECT_LINKS + NUM_SINGLY_INDIRECT_LINKS))
        {
            // Singly Indirect fetch
            block_index -= NUM_DIRECT_LINKS;
            iBlock = fsm->ReadIndirectBlock(node->GetBlockLocation(NUM_DIRECT_LINKS));
            block = iBlock->GetAddr(block_index);
            delete iBlock;
        } 
        else if (file_offset < BLOCK_SIZE*(NUM_DIRECT_LINKS + NUM_SINGLY_INDIRECT_LINKS + NUM_DOUBLY_INDIRECT_LINKS))
        {
            // Doubly Indirect fetch
            block_index -= NUM_DIRECT_LINKS + NUM_SINGLY_INDIRECT_LINKS;
            iBlock = fsm->ReadIndirectBlock(node->GetBlockLocation(NUM_DIRECT_LINKS+1));
            block = iBlock->GetAddr(block_index/NUM_SINGLY_INDIRECT_LINKS);
            delete iBlock;
            iBlock = fsm->ReadIndirectBlock(block);
            block = iBlock->GetAddr(block_index % NUM_SINGLY_INDIRECT_LINKS);
            delete iBlock;
        }
        else if (file_offset < BLOCK_SIZE*(NUM_DIRECT_LINKS + NUM_SINGLY_INDIRECT_LINKS + NUM_DOUBLY_INDIRECT_LINKS + NUM_TRIPLY_INDIRECT_LINKS))
        {
            // Triply Indirect fetch
            block_index -= NUM_DIRECT_LINKS + NUM_SINGLY_INDIRECT_LINKS + NUM_DOUBLY_INDIRECT_LINKS;
            iBlock = fsm->ReadIndirectBlock(node->GetBlockLocation(NUM_DIRECT_LINKS+2));
            block = iBlock->GetAddr(block_index/NUM_DOUBLY_INDIRECT_LINKS);
            delete iBlock;
            iBlock = fsm->ReadIndirectBlock(block);
            block = iBlock->GetAddr(block_index/NUM_SINGLY_INDIRECT_LINKS % NUM_SINGLY_INDIRECT_LINKS);
            delete iBlock;
            iBlock = fsm->ReadIndirectBlock(block);
            block = iBlock->GetAddr(block_index % NUM_SINGLY_INDIRECT_LINKS);
            delete iBlock;
        }
        else
        {
            cerr << "File too large for file system" << endl;
            exit(1);
        }

        fsm->GetSB()->AddFreeDataBlock(block);
        file_offset += BLOCK_SIZE;
    }
    return;

}
